package v1

import (
	"github.com/boombuler/barcode/qr"
	"go-gin-example/pkg/app"
	"go-gin-example/pkg/qrcode"
	"go-gin-example/pkg/setting"
	"go-gin-example/pkg/util"
	"go-gin-example/service/article"
	"go-gin-example/service/tag"
	"net/http"

	"github.com/astaxie/beego/validation"
	"github.com/gin-gonic/gin"
	"github.com/unknwon/com"
	"go.uber.org/zap"

	"go-gin-example/pkg/e"
)

// GetArticle
// @tags  文章管理
// @Summary 获取单个文章
// @Produce json
// @Param token query  string true "token"
// @Param id path int true "ID"
// @Success 200 {object} app.Response
// @Failure 500 {object} app.Response
// @Router /api/v1/articles/{id} [get]
func GetArticle(c *gin.Context) {
	appG := app.Gin{c}
	id := com.StrTo(c.Param("id")).MustInt()
	valid := validation.Validation{}
	valid.Min(id, 1, "id").Message("ID必须大于0")

	// 提前返回处理结果
	if valid.HasErrors() {
		app.MarkErrors(valid.Errors)
		appG.Response(http.StatusBadRequest, e.InvalidParams, nil)
		return
	}

	articleService := article.Article{ID: id}
	exists, err := articleService.ExistByID()
	if err != nil {
		zap.L().Info("", zap.Error(err))
		appG.Response(http.StatusInternalServerError, e.ErrorCheckExistArticleFail, nil)
		return
	}
	if !exists {
		appG.Response(http.StatusOK, e.ErrorNotExistArticle, nil)
		return
	}
	articleData, err := articleService.Get()
	if err != nil {
		zap.L().Info("", zap.Error(err))
		appG.Response(http.StatusInternalServerError, e.ErrorGetArticleFail, nil)
		return
	}
	appG.Response(http.StatusOK, e.SUCCESS, articleData)
}

// GetArticles
// @tags  文章管理
// @Summary 获取多个文章
// @Produce json
// @Param token query  string true "token"
// @Param state query  string true "state"
// @Param tagId query  int true "tagId"
// @Success 200 {object} app.Response
// @Failure 500 {object} app.Response
// @Router /api/v1/articles [get]
func GetArticles(c *gin.Context) {
	appG := app.Gin{c}
	valid := validation.Validation{}

	var state int = -1
	if arg := c.Query("state"); arg != "" {
		state = com.StrTo(arg).MustInt()
		valid.Range(state, 0, 1, "state").Message("状态只允许0或1")
	}

	var tagId int = -1
	if arg := c.Query("tag_id"); arg != "" {
		tagId = com.StrTo(arg).MustInt()
		valid.Min(tagId, 1, "tag_id").Message("标签ID必须大于0")
	}
	// 提前返回处理结果
	if valid.HasErrors() {
		app.MarkErrors(valid.Errors)
		appG.Response(http.StatusBadRequest, e.InvalidParams, nil)
		return
	}

	articleService := article.Article{
		TagID:    tagId,
		State:    state,
		PageNum:  util.GetPage(c),
		PageSize: setting.AppSetting.PageSize,
	}

	total, err := articleService.Count()
	if err != nil {
		appG.Response(http.StatusOK, e.ErrorCountArticleFail, nil)
		return
	}
	articles, err := articleService.GetAll()
	if err != nil {
		appG.Response(http.StatusOK, e.ErrorGetArticlesFail, nil)
		return
	}

	data := make(map[string]interface{})
	data["list"] = articles
	data["total"] = total
	appG.Response(http.StatusOK, e.SUCCESS, data)
}

type AddArticleForm struct {
	TagID         int    `form:"tag_id" valid:"Required;Min(1)"`
	Title         string `form:"title" valid:"Required;MaxSize(100)"`
	Desc          string `form:"desc" valid:"Required;MaxSize(255)"`
	Content       string `form:"content" valid:"Required;MaxSize(65535)"`
	CreatedBy     string `form:"created_by" valid:"Required;MaxSize(100)"`
	CoverImageUrl string `form:"cover_image_url" valid:"Required;MaxSize(255)"`
	State         int    `form:"state" valid:"Range(0,1)"`
}

// AddArticle
// @tags  文章管理
// @Summary 新增文章
// @Produce json
// @Param token query  string true "token"
// @Param tagId query int true "tagId"
// @Param title query string true "title"
// @Param desc query string false "desc"
// @Param content query string false "content"
// @Param cover_image_url query string true "cover_image_url"
// @Param created_by query string false "CreatedBy"
// @Success 200 {object} app.Response
// @Failure 500 {object} app.Response
// @Router /api/v1/articles [post]
func AddArticle(c *gin.Context) {
	var (
		appG = app.Gin{C: c}
		form AddArticleForm
	)
	httpCode, errCode := app.BindAndValid(c, &form)
	if errCode != e.SUCCESS {
		appG.Response(httpCode, errCode, nil)
		return
	}
	tagService := tag.Tag{ID: form.TagID}
	exist, err := tagService.ExistByID()
	if err != nil {
		appG.Response(http.StatusInternalServerError, e.ErrorCheckExistTagFail, nil)
		return
	}
	if !exist {
		appG.Response(http.StatusOK, e.ErrorNotExistTag, nil)
		return
	}

	articleService := article.Article{
		TagID:         form.TagID,
		Title:         form.Title,
		Desc:          form.Desc,
		Content:       form.Content,
		CoverImageUrl: form.CoverImageUrl,
		State:         form.State,
		CreatedBy:     form.CreatedBy,
	}

	if err := articleService.Add(); err != nil {
		zap.L().Info("", zap.Error(err))
		appG.Response(http.StatusInternalServerError, e.ErrorAddArticleFail, nil)
		return
	}
	appG.Response(http.StatusOK, e.SUCCESS, nil)
}

type EditArticleForm struct {
	ID            int    `form:"id" valid:"Required;Min(1)"`
	TagID         int    `form:"tag_id" valid:"Required;Min(1)"`
	Title         string `form:"title" valid:"Required;MaxSize(100)"`
	Desc          string `form:"desc" valid:"Required;MaxSize(255)"`
	Content       string `form:"content" valid:"Required;MaxSize(65535)"`
	ModifiedBy    string `form:"modified_by" valid:"Required;MaxSize(100)"`
	CoverImageUrl string `form:"cover_image_url" valid:"Required;MaxSize(255)"`
	State         int    `form:"state" valid:"Range(0,1)"`
}

// EditArticle
// @tags  文章管理
// @Summary 修改文章
// @Produce json
// @Param token query  string true "token"
// @Param id path int true "ID"
// @Param name query string true "Name"
// @Param title query string true "title"
// @Param desc query string false "desc"
// @Param content query string false "content"
// @Param cover_image_url query string true "cover_image_url"
// @Param modified_by query string false "modified_by"
// @Success 200 {object} app.Response
// @Failure 500 {object} app.Response
// @Router /api/v1/articles/{id} [put]
func EditArticle(c *gin.Context) {
	var (
		appG = app.Gin{C: c}
		form = EditArticleForm{ID: com.StrTo(c.Query("id")).MustInt()}
	)
	httpCode, errCode := app.BindAndValid(c, &form)
	if errCode != e.SUCCESS {
		appG.Response(httpCode, errCode, nil)
		return
	}

	articleService := article.Article{
		ID:            form.ID,
		TagID:         form.TagID,
		Title:         form.Title,
		Desc:          form.Desc,
		Content:       form.Content,
		CoverImageUrl: form.CoverImageUrl,
		ModifiedBy:    form.ModifiedBy,
		State:         form.State,
	}
	exists, err := articleService.ExistByID()
	if err != nil {
		appG.Response(http.StatusInternalServerError, e.ErrorCheckExistArticleFail, nil)
		return
	}
	if !exists {
		appG.Response(http.StatusOK, e.ErrorNotExistArticle, nil)
		return
	}

	tagService := tag.Tag{ID: form.TagID}
	exists, err = tagService.ExistByID()
	if err != nil {
		appG.Response(http.StatusInternalServerError, e.ErrorCheckExistTagFail, nil)
		return
	}

	if !exists {
		appG.Response(http.StatusOK, e.ErrorNotExistTag, nil)
		return
	}

	err = articleService.Edit()
	if err != nil {
		zap.L().Info("", zap.Error(err))
		appG.Response(http.StatusInternalServerError, e.ErrorEditArticleFail, nil)
		return
	}
	appG.Response(http.StatusOK, e.SUCCESS, nil)
}

// DeleteArticle
// @tags  文章管理
// @Summary 删除文章
// @Produce json
// @Param token query  string true "token"
// @Param id path int true "ID"
// @Success 200 {object} app.Response
// @Failure 500 {object} app.Response
// @Router /api/v1/articles/{id} [delete]
func DeleteArticle(c *gin.Context) {
	var appG = app.Gin{C: c}
	id := com.StrTo(c.Param("id")).MustInt()

	valid := validation.Validation{}
	valid.Min(id, 1, "id").Message("ID必须大于0")

	if valid.HasErrors() {
		app.MarkErrors(valid.Errors)
		appG.Response(http.StatusBadRequest, e.InvalidParams, nil)
		return
	}

	articleService := article.Article{ID: id}
	exist, err := articleService.ExistByID()
	if err != nil {
		appG.Response(http.StatusInternalServerError, e.ErrorCheckExistTagFail, nil)
		return
	}
	if !exist {
		appG.Response(http.StatusOK, e.ErrorNotExistArticle, nil)
		return
	}
	err = articleService.Delete()
	if err != nil {
		zap.L().Info("", zap.Error(err))
		appG.Response(http.StatusInternalServerError, e.ErrorDeleteArticleFail, nil)
		return
	}
	appG.Response(http.StatusOK, e.SUCCESS, nil)
}

const (
	QrcodeUrl = "https://www.baidu.com"
)

// GenerateArticlePoster
// @tags  文章管理
// @Summary 生成二维码海报
// @Produce json
// @Param token query  string true "token"
// @Success 200 {object} app.Response
// @Failure 500 {object} app.Response
// @Router /api/v1/articles/poster/generate [post]
func GenerateArticlePoster(c *gin.Context) {
	appG := app.Gin{c}
	articleService := &article.Article{}
	qr := qrcode.NewQrCode(QrcodeUrl, 300, 300, qr.M, qr.Auto) // 目前写死 gin 系列路径，可自行增加业务逻辑
	posterName := article.GetPosterFlag() + "-" + qrcode.GetQrCodeFileName(qr.URL) + qr.GetQrCodeExt()
	articlePoster := article.NewArticlePoster(posterName, articleService, qr)
	articlePosterBgService := article.NewArticlePosterBg(
		"bg.jpeg",
		articlePoster,
		&article.Rect{
			X0: 0,
			Y0: 0,
			X1: 550,
			Y1: 700,
		},
		&article.Pt{
			X: 125,
			Y: 298,
		},
	)

	_, filePath, err := articlePosterBgService.Generate()
	if err != nil {
		appG.Response(http.StatusOK, e.ErrorGenArticlePosterFail, nil)
		return
	}

	appG.Response(http.StatusOK, e.SUCCESS, map[string]string{
		"poster_url":      qrcode.GetQrCodeFullUrl(posterName),
		"poster_save_url": filePath + posterName,
	})
}
